/**
 * @param {number[][]} grid
 * @return {number}
 */
var orangesRotting = function (grid) {
  //行数 列数
  let m = grid.length
  let n = grid[0].length
  //队列（存放腐烂的橘子的坐标） 新鲜橘子的数量
  let queue = []
  let fresh = 0
  //将腐烂的橘子入队、统计新鲜橘子的数量
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (grid[i][j] === 2) {
        queue.push([i, j])//推入坐标
      } else if (grid[i][j] === 1) {
        fresh++
      }
    }
  }

  //如果没有新鲜的橘子，返回0
  if (fresh === 0) return 0


  //定义上下左右四个方向
  let direction = [[-1, 0], [1, 0], [0, 1], [0, -1]]
  //腐烂所有橘子需要的分钟数
  let min = 0
  //BFS：求腐烂所有橘子需要的分钟数，每一层可能会耗费一分钟（因为又可能没有橘子腐烂，不耗时）
  while (queue.length > 0) {
    let size = queue.length//当前层的橘子数量
    let infectedThisAround = false//当前层是否有橘子腐烂
    //处理队列中的所有橘子
    for (let i = 0; i < size; i++) {
      //队首元素出队 并 解构赋值成坐标
      const [r, c] = queue.shift()
      //遍历上下左右四个方向 并 解构赋值成坐标
      for (const [dr, dc] of direction) {
        //相邻橘子的坐标
        let nr = r + dr, nc = c + dc
        //如果该坐标有效且橘子新鲜
        if (nr >= 0 && nr < m && nc >= 0 && nc < n && grid[nr][nc] === 1) {
          fresh--//新鲜橘子数量-1
          grid[nr][nc] = 2//腐烂橘子
          queue.push([nr, nc])//腐烂橘子入队
          infectedThisAround = true//当前层有橘子腐烂
        }
      }
    }
    //如果当前层有橘子腐烂，min++
    if (infectedThisAround) min++
  }

  //所有橘子是否腐烂完毕：是的话返回分钟数，不是就返回-1
  return fresh == 0 ? min : -1
};